#!python
import wx
import pbfi
import util
import sys
import os

LIST_COLUMNS = (
        ( 'offset'   , 60 ),
        ( 'type'     , 120  ),
        ( 'value'    , 220  ),
        )

class BinaryFileViewWindow(wx.SplitterWindow, util.Subject):
    def __init__(self, parent, id):
        wx.SplitterWindow.__init__(self, parent, id, style=wx.SP_3D|wx.SP_BORDER)
        self.model              = None
        util.Subject.__init__(self)
       
        self.window_1_pane_2 = wx.Panel(self, -1)
        self.window_1_pane_1 = wx.Panel(self, -1)
        self.tree_ctrl_1 = wx.TreeCtrl(self.window_1_pane_1, -1, style=wx.TR_HAS_BUTTONS|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER)
        self.list_ctrl_1 = wx.ListCtrl(self.window_1_pane_2, -1, style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES|wx.SUNKEN_BORDER)
        
        for (position, name_and_size) in zip(xrange(len(LIST_COLUMNS)),LIST_COLUMNS):
            self.list_ctrl_1.InsertColumn(position, name_and_size[0])
            self.list_ctrl_1.SetColumnWidth(position, name_and_size[1])
        
        self.MapEvents()
        self.__do_layout() 
    
    def __do_layout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3.Add(self.tree_ctrl_1, 1, wx.EXPAND, 0)
        
        self.window_1_pane_1.SetSizer(sizer_3)
        sizer_2.Add(self.list_ctrl_1, 1, wx.EXPAND, 0)
        
        self.window_1_pane_2.SetSizer(sizer_2)
        self.SplitVertically(self.window_1_pane_1, self.window_1_pane_2)
        
        sizer_1.Add(self, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()

    def MapEvents(self):
        pass
    
    def UpdateView(self, dc = None):
        pass
        
    def setModel(self, model):
        """change model"""
        if self.model is not None:
            self.model.detatch(self)
        self.model = model
        self.model.attach(self)
        self.update()
    
    def blocks_to_widgets(self,blocks,row):
        for block in blocks:
            if block['format'] == 'array':
                self.blocks_to_widgets(block['value'],row)
            else:
                self.list_ctrl_1.InsertStringItem(row,"")
                if 'name' in block:
                    self.list_ctrl_1.SetStringItem(row,0,str(block['name']))
                self.list_ctrl_1.SetStringItem(row,2,str(block['value']))
                row = row + 1
    
    def update(self, subject=None):
        if self.model and self.model.blocks:
            pass
            self.list_ctrl_1.DeleteAllItems()
            
            blocks = self.model.blocks 
            self.blocks_to_widgets(blocks,0) 
            
            self.Layout()
    
if sys.platform == 'win32':
    wildcard = "All files (*.*)|*.*"
    wildcard_xml = "Model file (*.xml)|*.xml"
else:
    wildcard = "All files|*"
    wildcard_xml = "Model file|*.xml"

def idgen():
    id = wx.ID_HIGHEST
    while True:
        id +=1
        yield id
id_iter = idgen()

ID_OPEN = wx.ID_OPEN
ID_OPEN_MODEL = id_iter.next() 
ID_RELOAD = wx.ID_REVERT
ID_RELOAD_MODEL = id_iter.next() 
ID_CLOSE = wx.ID_CLOSE    
ID_EXIT = wx.ID_EXIT           

class MainFrame(wx.Frame):
    """
    """
    def __init__(self, parent,id ,title):
        wx.Frame.__init__(self, parent,id,title,wx.DefaultPosition,wx.Size(300,250))

        # Menu Bar
        self.menubar = wx.MenuBar()
        self.SetMenuBar(self.menubar)
        self.menu_file = wx.Menu()
        self.menu_file.Append(ID_OPEN_MODEL, "&Open model...", "", wx.ITEM_NORMAL)
        self.menu_file.Append(ID_RELOAD_MODEL, "&Reload model...", "", wx.ITEM_NORMAL)
        self.menu_file.Append(ID_OPEN, "&Open...\tCtrl+O", "", wx.ITEM_NORMAL)
        self.menu_file.Append(ID_RELOAD, "&Reload\tCtrl+R", "", wx.ITEM_NORMAL)
        self.menu_file.Append(ID_CLOSE, "&Close\tCtrl+W", "", wx.ITEM_NORMAL)
        self.menu_file.AppendSeparator()
        self.menu_file.Append(ID_EXIT, "&Quit", "", wx.ITEM_NORMAL)
        self.menubar.Append(self.menu_file, "&File")
        
        # Menu Bar end
        self.statusbar = self.CreateStatusBar(2)

        self.__set_properties()
        self.__do_layout()
        self.__attach_events()
        self.inspector_view = BinaryFileViewWindow(self, -1)
        self.inspector_view.attach(self)
        self.inspector_view.SetFocus()
        
    def __set_properties(self):
        self.SetTitle("PBFI")
        self.statusbar.SetStatusWidths([-5, -1])
        # statusbar fields
        statusbar_fields = ["Ready", ""]
        for i in range(len(statusbar_fields)):
            self.statusbar.SetStatusText(statusbar_fields[i], i)

    def __do_layout(self):
        self.Layout()

    def __attach_events(self):
        wx.EVT_MENU(self, ID_OPEN,           self.onOpen)
        wx.EVT_MENU(self, ID_OPEN_MODEL,     self.onOpenModel)
        wx.EVT_MENU(self, ID_RELOAD,         self.onReload)
        wx.EVT_MENU(self, ID_RELOAD_MODEL,   self.onReloadModel)
        wx.EVT_MENU(self, ID_CLOSE,          self.onCloseFile)
        wx.EVT_MENU(self, ID_EXIT,           self.onWindowClose)

    def onWindowClose(self, event):
        pass

    def open(self, path):
        self.file_inspector.load(path)
        self.file_inspector.update()
    
    def open_model(self, path):
        self.file_inspector.load_model(path)
        self.file_inspector.update()
        
    def onOpen(self, event):
        dlg = wx.FileDialog(self, "Open...", os.getcwd(), "", wildcard, wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.open(path)
        dlg.Destroy()
    
    def onOpenModel(self, event):
        dlg = wx.FileDialog(self, "Open model...", os.getcwd(), "", wildcard_xml, wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.open_model(path)
        dlg.Destroy()
    
    def onReload(self, event):
        pass
    
    def onReloadModel(self, event):
        pass

    def onCloseFile(self, event):
        pass

    def update(self, subject=None):
        """view or data model has changed"""
        pass

    def setModel(self, file_inspector):
        self.file_inspector= file_inspector
        self.file_inspector.attach(self)
        self.inspector_view.setModel(file_inspector)


class MainApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        self.frame_main = MainFrame(None, -1, "PBFI")
        self.SetTopWindow(self.frame_main)
        self.frame_main.Show(1)
        return 1

    def setModel(self, file_inspector):
        self.frame_main.setModel(file_inspector)
        self.frame_main.update()

if __name__ == "__main__":
    file_inspector = pbfi.BinaryFileInspector()
    app = MainApp()
    app.setModel(file_inspector)
    if len(sys.argv) == 2:
        app.frame_main.open(sys.argv[1])
    app.MainLoop()

